/*
 * Copyright (c) 2021 Futurewei Technologies, Inc.
 *
 * clang2mpl is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
 * Mulan PSL v2 for more details.
 */
// RUN: %clang2mpl --ascii --verify %s -- --target=aarch64-linux-elf
// RUN: cat %m | %FileCheck %s

void foo(int a) {
  int x = 0;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: while (ne i32 i32 (dread i32 %a, constval i32 0)) {
  // CHECK-NEXT: }
  while (a != 0)
    ;

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: while (lt i32 i32 (dread i32 %x, dread i32 %a)) {
  while (x < a) {
    // CHECK: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
    x++;
    // CHECK: }
  }

  // CHECK: LOC 2 [[#WHILELINE1: @LINE + 4 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POSTNUM1:]] 0 (dread i32 %x)
  // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: while (lt i32 i32 (dread i32 %post.[[#POSTNUM1]], dread i32 %a)) {
  while (x++ < a)
    // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
    // CHECK-NEXT: dassign %a 0 (dread i32 %x)
    a = x;
    // CHECK: LOC 2 [[#WHILELINE1]]{{$}}
    // CHECK-NEXT: dassign %post.[[#POSTNUM1]] 0 (dread i32 %x)
    // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dowhile {
  do
  // CHECK: } (ne i32 i32 (dread i32 %a, constval i32 0))
    ; while(a != 0);

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dowhile {
  do {
    // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
    // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
    ++x;
    // CHECK: } (lt i32 i32 (dread i32 %x, dread i32 %a))
  } while (x < a);

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dowhile {
  do {
    // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
    // CHECK-NEXT: dassign %a 0 (dread i32 %x)
    a = x;
    // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
    // CHECK-NEXT: dassign %post.[[#POSTNUM2:]] 0 (dread i32 %x)
    // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
    // CHECK-NEXT: } (lt i32 i32 (dread i32 %post.[[#POSTNUM2]], dread i32 %a))
  } while (x++ < a);

  // CHECK: LOC 2 [[# @LINE + 5 ]]{{$}}
  // CHECK-NEXT: dassign %x 0 (constval i32 0)
  // CHECK-NEXT: while (lt i32 i32 (dread i32 %x, dread i32 %a)) {
  // CHECK-NEXT:   dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: }
  for (x = 0; x < a; ++x)
    ;

  // CHECK: LOC 2 [[# @LINE + 5 ]]{{$}}
  // CHECK-NEXT: dassign %x 0 (constval i32 0)
  // CHECK-NEXT: while (lt i32 i32 (dread i32 %x, dread i32 %a)) {
  // CHECK-NEXT:   dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: }
  for (x = 0; x < a; ++x) { }

  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: while (constval i32 1) {
  for (x++; ; )
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT:   dassign %a 0 (dread i32 %x)
  // CHECK-NEXT: }
    a = x;

  // CHECK: LOC 2 [[#FORLINE1: @LINE + 4 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POSTNUM3:]] 0 (dread i32 %x)
  // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: while (gt i32 i32 (dread i32 %post.[[#POSTNUM3]], dread i32 %a)) {
  for (; x++ > a; )
    // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
    // CHECK-NEXT: dassign %a 0 (dread i32 %x)
    a = x;
    // CHECK: LOC 2 [[#FORLINE1]]{{$}}
    // CHECK-NEXT: dassign %post.[[#POSTNUM3]] 0 (dread i32 %x)
    // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: while (ne i32 i32 (dread i32 %a, constval i32 0)) {
  while(a != 0) {
    // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
    // CHECK-NEXT: goto @L_EXIT[[#LABEL1:]]
    break;
  // CHECK: }
  // CHECK-NEXT: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: @L_EXIT[[#LABEL1]]
  }

  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: while (ne i32 i32 (dread i32 %a, constval i32 0)) {
  while(a != 0) {
    // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
    // CHECK-NEXT: goto @L_END[[#LABEL2:]]
    continue;
    // CHECK: @L_END[[#LABEL2]]   }
  }


  while(a++ != 0) {
    // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
    // CHECK-NEXT: if (eq i32 i32 (dread i32 %a, dread i32 %x)) {
    // CHECK-NEXT:   goto @L_EXIT[[#LABEL3:]]
    // CHECK-NEXT: }
    if (a == x) break;
    // CHECK: dassign %post.[[#]] 0 (dread i32 %a)
    // CHECK-NEXT: dassign %a 0 (add i32 (dread i32 %a, constval i32 1))
    // CHECK-NEXT: }
    // CHECK-NEXT: LOC 2 [[# @LINE + 2 ]]{{$}}
    // CHECK-NEXT: @L_EXIT[[#LABEL3]]
  }

  while(a++ != 0) {
    // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
    // CHECK-NEXT: if (eq i32 i32 (dread i32 %a, dread i32 %x)) {
    // CHECK-NEXT:   goto @L_END[[#LABEL4:]]
    // CHECK-NEXT: }
    if (a == x) continue;
    // CHECK: @L_END[[#LABEL4]]
    // CHECK-NEXT: dassign %post.[[#]] 0 (dread i32 %a)
    // CHECK-NEXT: dassign %a 0 (add i32 (dread i32 %a, constval i32 1))
  }
}
